package com.itfreer.data.syn.base;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.PostConstruct;

import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import com.itfreer.data.syn.DataSynConfigService;
import com.itfreer.data.syn.DataSynItemService;
import com.itfreer.data.syn.DataSynLogService;
import com.itfreer.data.syn.DataSynService;
import com.itfreer.data.syn.entity.DataSynEntity;
import com.itfreer.data.syn.entity.DataSynLogEntity;
import com.itfreer.form.api.PageInfo;
import com.itfreer.form.api.dictionary.DictionaryEntity;

/**
 * 定义通知发送任务，用于spring的任务 在此任务中，启动NoticeSendStrategy
 */
@Component
public class DataSynTask implements Job, ApplicationContextAware {

	protected static ApplicationContext applicationContext;

	@Autowired(required = false)
	@Qualifier("datasynScheduler")
	private Scheduler scheduler;

	@Autowired
	private DataSynPara dataSynPara;

	public DataSynTask() {
	}

	@PostConstruct
	public void scheduleCleanerJob() {
		try {
			if (shouldScheduleCleanerJob()) {
				final JobDetail job = JobBuilder.newJob(getClass())
						.withIdentity(getClass().getSimpleName().concat(UUID.randomUUID().toString())).build();

				Calendar nowTime = Calendar.getInstance();
				nowTime.add(Calendar.SECOND, dataSynPara.getStartDelay());

				final Trigger trigger = TriggerBuilder.newTrigger()
						.withIdentity(getClass().getSimpleName().concat(UUID.randomUUID().toString()))
						.startAt(nowTime.getTime()).withSchedule(SimpleScheduleBuilder.simpleSchedule()
								.withIntervalInSeconds(dataSynPara.getRefreshInterval()).repeatForever())
						.build();

				scheduler.scheduleJob(job, trigger);
			} else {

			}
		} catch (final Exception e) {
		}

	}

	@Override
	public void execute(final JobExecutionContext jobExecutionContext) throws JobExecutionException {
		try {
			// 清日志
			clearLog();
			// 定时执行
			syn();
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	// 数据同步
	private void syn() {
		DataSynService dataSynService = applicationContext.getBean(DataSynService.class);
		DataSynLogService dataSynLogService = applicationContext.getBean(DataSynLogService.class);
		DataSynConfigService dataSynConfigService = applicationContext.getBean(DataSynConfigService.class);

		DataSynPara synPara = applicationContext.getBean(DataSynPara.class);
		int tryTime = synPara.getTryTimes();
		if (tryTime <= 0) {
			tryTime = 3;
		}
		// 查询同步数据
		Map<String, Object> where = new HashMap<>();
		where.put("all", false);
		where.put("failTimes:<", tryTime);
		Long count = dataSynService.getCounts(where);
		if (count == null || count <= 0) {
			return;
		}

		Integer indexs = (int) (count / 100);
		if (indexs * 100 < count) {
			indexs += 1;
		}

		Map<String, Integer> order = new HashMap<>();
		order.put("table", 0);
		order.put("addDate", 0);
		PageInfo pInfo = new PageInfo();
		pInfo.setWhere(where);
		pInfo.setOrder(order);
		pInfo.setPageSize(100);

		for (int i = 1; i <= indexs; i++) {
			pInfo.setPageIndex(i);
			List<DataSynEntity> datas = dataSynService.getEntitys(pInfo);
			for (DataSynEntity data : datas) {
				// 同步，并记录日志
				// 3.调用配置进行数据同步处理
				List<DictionaryEntity> items = dataSynConfigService.getItems(data.getTable());
				// 4.记录失败项
				List<String> fails = new ArrayList<>();
				String[] oldFails = data.getFails();
				for (DictionaryEntity item : items) {
					// 过滤已发送不再重复发送
					if (oldFails != null && oldFails.length > 0) {
						boolean hasId = false;
						for (String f : oldFails) {
							if (f.equals(item.getId())) {
								hasId = true;
								break;
							}
						}
						if (!hasId) {
							continue;
						}
					}
					DataSynItemService synService = (DataSynItemService) applicationContext.getBean(item.getAbbreviation());
					String err = null;
					if (data.getType().equals("add")) {
						err = synService.add(data.getData(), item.getInfo());
					} else if (data.getType().equals("delete")) {
						err = synService.delete(data.getData(), item.getInfo());
					} else if (data.getType().equals("update")) {
						err = synService.update(data.getData(), item.getInfo());
					}

					// 记录日志
					DataSynLogEntity log = new DataSynLogEntity();
					log.setId(UUID.randomUUID().toString().replace("-", ""));
					log.setAddDate(new Date());
					log.setSynid(data.getId());
					log.setConfigid(item.getId());
					if (err == null) {
						log.setState(true);
					} else {
						log.setState(false);
						log.setInfo(err);
						fails.add(item.getId());
					}
					dataSynLogService.add(log);
				}

				// 记录到总信息中
				if (fails.size() <= 0) {
					data.setAll(true);
					data.setFails(null);
					dataSynService.update(data);
				} else {
					data.setAll(false);
					String[] ids = new String[fails.size()];
					ids = fails.toArray(ids);
					data.setFails(ids);
					Integer failTimes = data.getFailTimes();
					if (failTimes == null) {
						failTimes = 0;
					}
					failTimes += 1;
					data.setFailTimes(failTimes);
					dataSynService.update(data);
					// 失败了就暂时停止
					return;
				}
			}
		}

	}

	// 清除日志，只保留失败的数据，成功的数据，只保留30天
	private void clearLog() {
		DataSynService dataSynService = applicationContext.getBean(DataSynService.class);
		DataSynLogService dataSynLogService = applicationContext.getBean(DataSynLogService.class);

		dataSynService.deleteLogs(30);
		dataSynLogService.deleteLogs(30);
	}

	@Override
	public void setApplicationContext(ApplicationContext appContext) throws BeansException {
		applicationContext = appContext;
	}

	private boolean shouldScheduleCleanerJob() {
		if (dataSynPara.getStartDelay() > 0 && applicationContext.getParent() == null && scheduler != null) {
			return true;
		}
		return false;
	}
}
